package cn.hsa.xxx.placeOrder.service.Impl;

import cn.hsa.xxx.api.dto.BookCommodityDTO;
import cn.hsa.xxx.api.dto.BookInfoDTO;
import cn.hsa.xxx.api.dto.BookTypeDTO;
import cn.hsa.xxx.api.service.BookCommodityService;
import cn.hsa.xxx.api.service.BookInfoService;
import cn.hsa.xxx.api.service.BookTypeService;
import cn.hsa.xxx.bookOrder.dto.OrderDTO;
import cn.hsa.xxx.bookOrder.dto.OrderDetailsDTO;
import cn.hsa.xxx.bookOrder.service.OrderDetailsService;
import cn.hsa.xxx.bookOrder.service.OrderService;
import cn.hsa.xxx.api.dto.CommodityDTO;
import cn.hsa.xxx.api.service.DiscountService;
import cn.hsa.xxx.api.service.PlaceOrderService;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class PlaceOrderServiceImpl implements PlaceOrderService {

    @Resource(name = "bookInfo")
    private BookInfoService bookInfoService;

    @Resource(name = "bookType")
    private BookTypeService bookTypeService;

    @Resource(name = "bookCommodity")
    private BookCommodityService bookCommodityService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderDetailsService orderDetailsService;

    @Autowired
    private DiscountService discountService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Pair<Float, Float> getPreCalculated(List<CommodityDTO> commodityDTOList) {
        //总折扣之后价格
        Float sumDiscountPrice = new Float(0.0);
        //商品原本总价
        Float sumPrice = new Float(0.0);

        //将商品按照书籍类型分类 类型-该类型总价
        Map<String, Float>  typeMap = new HashMap<>();
        //将所有类型的书籍分类
        for (CommodityDTO commodityDTO : commodityDTOList) {
            String bookUuid = commodityDTO.getBookUuid();
            BookInfoDTO bookInfoDTO = bookInfoService.get(bookUuid);
            String bookTypeUuid = bookInfoDTO.getBookTypeUuid();
            BookTypeDTO bookTypeDTO = bookTypeService.get(bookTypeUuid);
            String bookTypeName = bookTypeDTO.getBookTypeName();
            //该商品总价
            Float commonPrice = commodityDTO.getQuantity()*commodityDTO.getCommodityPrice();
            //map中该类型为空则添加，不为空则修改
            if(typeMap.get(bookTypeName) == null) {
                typeMap.put(bookTypeName, commonPrice);
            }else {
                //更新总价
                Float price = typeMap.get(bookTypeName)+commonPrice;
                //把原数据覆盖掉
                typeMap.put(bookTypeName, price);
            }
        }

        //计算折扣券折扣之后价格
        for(Map.Entry<String, Float> entry : typeMap.entrySet()) {
            String bookTypeName = entry.getKey();
            Float price = entry.getValue();
            Set<String> discountIdSet = discountService.getIdOfType(bookTypeName);

            //叠加计算商品总价
            sumPrice += price;
            log.warn("price!!!!!!!!!!!!: {}",price);

            //折扣后的最低价格
            Float minPrice = price;
            for (String discountId : discountIdSet) {
                //获取折扣的阈值
                Float indexes = (Float) discountService.getDiscount(discountId, DiscountService.INDEXES);

                //获取折扣的优惠力度
                Float preferentialValue = (Float) discountService.getDiscount(discountId, DiscountService.PREFERENTIAL_VALUE);
                log.warn("!!!!!!!!!!!!!!!!!!!!!!!!discount:::indexes:{},preferentialValue{},", indexes,preferentialValue);
                //如果满足折扣条件
                if(indexes <= price) {
                    Float discountPrice = price*preferentialValue;
                    if(discountPrice < minPrice) {
                        minPrice = discountPrice;
                    }
                    log.warn("minPrice: {}", minPrice);
                }
            }
            //在汇总价格中加入该类书籍折扣后的价格
            sumDiscountPrice += minPrice;
            log.warn("sumDiscountPrice: {}",sumDiscountPrice);
        }

        //计算满减券满减之后的价格
        Set<String> fullDiscountIdSet = discountService.getIdOfType(DiscountService.FULL_DISCOUNT);
        //初始化最低满减后价格
        Float minFullDiscountPrice = sumDiscountPrice;
        for (String fullDiscountId : fullDiscountIdSet) {
            //获取满减阈值
            Float indexes = (Float)discountService.getDiscount(fullDiscountId, DiscountService.INDEXES);

            //获取满减优惠力度
            Float preferentialValue = (Float) discountService.getDiscount(fullDiscountId, DiscountService.PREFERENTIAL_VALUE);
            log.warn("!!!!!!!!!!!!!!!!!!!!!!!!fullDiscount:::indexes:{},preferentialValue{}", indexes,preferentialValue);
            //如果满足折扣条件
            if(indexes <= sumDiscountPrice) {
                Float fullDiscountPrice = sumDiscountPrice-preferentialValue;
                if(fullDiscountPrice < minFullDiscountPrice) {
                    minFullDiscountPrice = fullDiscountPrice;
                }
            }
        }
        //将得到的最低满减后价格赋值给总价格
        sumDiscountPrice = minFullDiscountPrice;

        // 获取不可叠加使用的优惠券优惠之后的价格进行对比
        Float minNoSuperDiscountPrice = sumPrice;
        Set<String> noSuperDiscountIdSet = discountService.getIdOfType(DiscountService.NO_SUPER_DISCOUNT);
        for (String noSuperDiscountId : noSuperDiscountIdSet) {
            //获取不可叠加券的折扣阈值
            Float indexes = (Float)discountService.getDiscount(noSuperDiscountId, DiscountService.INDEXES);

            //获取不可叠加券的优惠力度
            Float preferentialValue = (Float) discountService.getDiscount(noSuperDiscountId, DiscountService.PREFERENTIAL_VALUE);
            log.warn("!!!!!!!!!!!!!!!!!!!!!!!!noSuper:::indexes:{},preferentialValue:{}", indexes,preferentialValue);
            log.warn("minNoSuperDiscountPrice: {} sumPrice: {}", minNoSuperDiscountPrice, sumPrice);
            //如果满足折扣条件
            if(indexes <= sumPrice) {
                Float fullDiscountPrice = sumPrice*preferentialValue;
                if(fullDiscountPrice < minNoSuperDiscountPrice) {
                    minNoSuperDiscountPrice = fullDiscountPrice;
                }
            }
        }
        log.warn("sumDiscountPrice: {},minFullDiscountPrice: {}", sumDiscountPrice, minNoSuperDiscountPrice);
        //选取折扣优惠力度最大的价格，将可叠加券的优惠价格和总优惠价格进行对比
        return new Pair(sumPrice, Math.min(sumDiscountPrice,minNoSuperDiscountPrice));
    }

    @Override
    @Transactional
    public Boolean addPlaceOrderList(List<CommodityDTO> commodityDTOList, String description) throws Exception {
        Pair<Float, Float> preCalculatedPrice = getPreCalculated(commodityDTOList);
        //获取折扣前的总价格
        Float sumPrice = preCalculatedPrice.getKey();
        //获取折扣后的总价格
        Float discountPrice = preCalculatedPrice.getValue();
        //获取总商品数量
        int sumQuantity = 0;
        for (CommodityDTO commodityDTO : commodityDTOList) {
            sumQuantity += commodityDTO.getQuantity();
        }
        //获取单件折扣力度
        Float singleDiscount = (sumPrice-discountPrice)/sumQuantity;

        //进行订单表的修改
        //设置订单uuid
        String orderUuid = "orderList"+(Math.random()*1000000)+(new Date()).toString();
        orderService.add(new OrderDTO(orderUuid, discountPrice, new Date(), "1", description, new Date(), new Date()));

        //进行订单明细表的修改
        for (CommodityDTO commodityDTO : commodityDTOList) {
            String bookCommodityUuid = commodityDTO.getBookCommodityUuid();
            Integer commodityQuantity = commodityDTO.getQuantity();
            //订单明细uuid
            String orderDetailsUuid = "orderDetail"+bookCommodityUuid+(Math.random()*1000000)+(new Date()).toString();
            //将订单明细表行加入数据库
            orderDetailsService.add(new OrderDetailsDTO(orderDetailsUuid,orderUuid,bookCommodityUuid,commodityQuantity,new Date(),new Date()));

            //将销售数据存入缓存
            putSalesMonitor(commodityDTO, singleDiscount);
        }

        //进行商品表的修改
        for (CommodityDTO commodityDTO : commodityDTOList) {
            String bookCommodityUuid = commodityDTO.getBookCommodityUuid();
            //获取商品表对象
            BookCommodityDTO bookCommodityDTO = bookCommodityService.get(bookCommodityUuid);
            //获取下完订单之后的商品数量
            int quantity = bookCommodityDTO.getShelvesRemainingQuantity()-commodityDTO.getQuantity();
            if(quantity < 0) {
                throw new Exception("订单中商品数量有误，超过商品剩余总数量");
            }
            //更新商品数量
            bookCommodityDTO.setShelvesRemainingQuantity(quantity);
            //更新商品时间
            bookCommodityDTO.setUpdateTime(new Date());
            //提交更新
            bookCommodityService.update(bookCommodityDTO);
        }
        return true;
    }

    /**
     * 将单条销售数据存入缓存
     * @param commodityDTO
     * @param singleDiscount
     */
    private void putSalesMonitor(CommodityDTO commodityDTO, Float singleDiscount) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH");
        String bookUuid = commodityDTO.getBookUuid();
        //设置每小时存入的数据key
        String key = "hourly"+"_"+sdf.format(new Date())+"_"+bookUuid;
        //获取bookTypeUuid
        String bookTypeUuid = bookInfoService.get(bookUuid).getBookTypeUuid();
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
        Map<Object, Object> salesMap = new HashMap();
        salesMap.put("bookUuid", bookUuid);
        salesMap.put("bookTypeUuid", bookTypeUuid);
        salesMap.put("statisticalTime", sdf.format(new Date()));
        //如果缓存中该小时该类型没有数据，则存入,有数据则更新
        if(entries == null) {
            Float commonPrice = (commodityDTO.getCommodityPrice()-singleDiscount)*commodityDTO.getQuantity();
            salesMap.put("dealAmount", commonPrice);
            salesMap.put("saleCount", commodityDTO.getQuantity());
            redisTemplate.opsForHash().putAll(key, salesMap);
        } else {
            Float commonPrice = (Float) entries.get("dealAmount")+(commodityDTO.getCommodityPrice()-singleDiscount)*commodityDTO.getQuantity();
            salesMap.put("dealAmount", commonPrice);
            Float commonQuantity = (Float) entries.get("saleCount")+commodityDTO.getQuantity();
            salesMap.put("saleCount", commonQuantity);
            redisTemplate.opsForHash().putAll(key, salesMap);
        }
        //设置过期时间两天
        redisTemplate.expire(key, 2, TimeUnit.DAYS);
    }


}
